#include "main.h"
#include "stdio.h"
#include "board_bsp.h"
#include "ring_buffer.h"
#include "shell.h"
#include "app_lcd_main.h"

#define GETTIMEOUT 100 // unit:ms

uint8_t bufComWithTOC4000[4];
ring_buffer_t rbComWithTOC4000;

static int rs485SendState;
static int rs485RecvState;
static uint8_t rs485RecvCMD;
static uint8_t rs485RecvLen;
static uint8_t rs485RecvData[256];
static bool rs485RecvFlag;
static uint8_t rs485RecvError;

extern Shell shell;

// #define  printf(format, ...)  shellPrint(&shell, format, ##__VA_ARGS__)

static inline bool HaveRs485Data(void)
{
    return rs485RecvFlag;
}

static inline bool IsRs485GetRightData(void)
{
    return rs485RecvError == 0;
}

static void handleSendData(uint8_t data)
{
    switch (data)
    {
    case 0x01:
    {
        static const uint8_t buf[] = {0xAA, 0xAA, 0x01, 0x00, 0x01, 0xFF, 0xFF};
        rs485Write((uint8_t *)buf, sizeof(buf));
    }
    break;

    default:
        break;
    }
}

// 处理正确信息
static void handleRightData(uint8_t data)
{
    switch (data)
    {
    case 0x81:
    {
        if (rs485RecvLen == 16)
        {
            union 
            {
                float f;
                uint8_t u8[4];
            }converter;
            converter.u8[0] = rs485RecvData[0];
            converter.u8[1] = rs485RecvData[1];
            converter.u8[2] = rs485RecvData[2];
            converter.u8[3] = rs485RecvData[3];
            // printf("TOC: %f\r\n", converter.f);
            Display_Line_A(converter.f, CAL_TOC);
            converter.u8[0] = rs485RecvData[4];
            converter.u8[1] = rs485RecvData[5];
            converter.u8[2] = rs485RecvData[6];
            converter.u8[3] = rs485RecvData[7];
            // printf("C1_t: %f\r\n", converter.f);
            Display_Line_B(converter.f, CAL_conductivity);
            converter.u8[0] = rs485RecvData[8];
            converter.u8[1] = rs485RecvData[9];
            converter.u8[2] = rs485RecvData[10];
            converter.u8[3] = rs485RecvData[11];
            // printf("T1_t: %f\r\n", converter.f);
            Display_Line_C(converter.f, CAL_temp);
            converter.u8[0] = rs485RecvData[12];
            converter.u8[1] = rs485RecvData[13];
            converter.u8[2] = rs485RecvData[14];
            converter.u8[3] = rs485RecvData[15];
            // printf("C1_u: %f\r\n", converter.f);
            Display_Line_D(converter.f, CAL_conductivityU);
        }
    }
    /* code */
    break;

    default:
        printf("get cmd: %02X\r\n", data);
        break;
    }
    rs485RecvFlag = 0;
}

// 处理错误信息
void handleErrorData(uint8_t data)
{
    printf("get error: %02X\r\n", data);
    rs485RecvFlag = 0;
}

static void ComWithTOC4000Send(void)
{
    static uint8_t get;
    static uint32_t tick;
    switch (rs485SendState)
    {
    case 0:
    {
        if (rb_read_byte(&rbComWithTOC4000, &get) == true)
        {
            // 发送消息
            handleSendData(get);
            rs485SendState = 1;
        }
    }
    break;
    case 1:
    {
        tick = HAL_GetTick();
        rs485SendState = 2;
    }
    break;
    case 2:
    {
        if (HaveRs485Data() == true)
        {

            if (IsRs485GetRightData() == true)
            {
                handleRightData(rs485RecvCMD);
            }
            else
            {
                // 处理错误信息
                handleErrorData(rs485RecvError);
            }
            rs485SendState = 0;
        }
        else
        {
            rs485SendState = 3;
        }
    }
    break;
    case 3:
    {
        if (HAL_GetTick() - tick > GETTIMEOUT)
        {
            // 处理错误信息
            const uint8_t timeout = 0;
            handleErrorData(timeout);
            rs485SendState = 0;
        }
        else
        {
            rs485SendState = 2;
        }
    }
    break;
    default:
        break;
    }
}

static void ComWithTOC4000Recv(void)
{
    static uint8_t idx;
    static uint8_t cs;
    if (rs485SendState != 0)
    {
        uint8_t get;
        if (rs485Read(&get, 1))
        {
            printf("get data: %02X , state: %d\r\n", get, rs485RecvState);
            switch (rs485RecvState)
            {
            case 0:
                if (get == 0xAA)
                {
                    rs485RecvState = 1;
                }
                break;
            case 1:
                if (get == 0xAA)
                {
                    rs485RecvState = 2;
                    cs = 0;
                }
                else
                {
                    rs485RecvError = 1;
                    rs485RecvState = 8;
                    rs485RecvFlag = true;
                }
                break;
            case 2:
            {
                if (get & 0x80)
                {
                    cs += get;
                    rs485RecvCMD = get;
                    rs485RecvState = 3;
                }
                else
                {
                    rs485RecvState = 0;
                }
            }
            break;
            case 3:
            {
                cs += get;
                rs485RecvLen = get;
                idx = 0;
                if (get == 0)
                {
                    rs485RecvState = 5;
                }
                else
                {
                    rs485RecvState = 4;
                }
            }
            break;
            case 4:
            {
                cs += get;
                rs485RecvData[idx++] = get;
                if (idx >= rs485RecvLen)
                {
                    rs485RecvState = 5;
                }
            }
            break;
            case 5:
            {
                if (cs == get)
                {
                    rs485RecvState = 6;
                }
                else
                {
                    rs485RecvError = 2;
                    rs485RecvState = 8;
                    rs485RecvFlag = true;
                }
            }
            break;
            case 6:
            {
                if (get == 0xFF)
                {
                    rs485RecvState = 7;
                }
                else
                {
                    rs485RecvError = 3;
                    rs485RecvState = 8;
                    rs485RecvFlag = true;
                }
            }
            break;
            case 7:
            {
                if (get == 0xFF)
                {
                    rs485RecvError = 0;
                    rs485RecvState = 8;
                    rs485RecvFlag = true;
                }
                else
                {
                    rs485RecvError = 3;
                    rs485RecvState = 8;
                    rs485RecvFlag = true;
                }
            }
            break;
            case 8:

                break;
            default:
                break;
            }
        }
    }
    else
    {
        rs485Rst();
        rs485RecvState = 0;
    }
}

// PUBILC
bool rs485AppInit(void)
{
    rb_init(&rbComWithTOC4000, bufComWithTOC4000, sizeof(bufComWithTOC4000));
    rs485SendState = 0;
    return true;
}

bool MainCMD(uint8_t cmd)
{
    return rb_write_byte(&rbComWithTOC4000, cmd);
}

bool rs485AddCMD(uint8_t cmd)
{
    return rb_write_byte(&rbComWithTOC4000, cmd);
}

void rs485AppLoop(void)
{
    ComWithTOC4000Recv();
    ComWithTOC4000Send();
}
